#pragma once

//stack to store the world matrix
#include <stack>
using std::stack;

//list of nodes
#include <list>
using std::list;

//root
class SGNode;

//specific node class
class SGNodeTranslate;
class SGNodeSeparator;
class SGNodeScale;
class SGNodeRotate;
class SGNodePrimitive;
class IPrimitive; //necessary to create a primitive node
class SGNodeMaterial;
class CMaterial; //necessary to create a material node
class SGNodeLookAt;
class SGNodeDirectionalLight;
class CDirectionalLight; //necessary to create a directional light node
class SGNodePointLight;
class CPointLight; //necessary to create a point light node

//matrix class
#include "CMatrix.h"

/*scenegraph class organized as a tree. Used to update the scene before every frame. Can create nodes.*/
class SGTree
{
private:
	//singleton instance
	static SGTree*	_instance;

	//pointer to the root of the scenegraph
	SGNode*			_root;

	//current value of the world matrix in the scenegraph
	CMatrix			_value;

	//matrix stack used to push and pop world matrix
	stack<CMatrix>	_stack;

	//Storage of node's pointer
	list<SGNode*> _nodesList;

public:
	//used to get the unique instance of the object SGTree. Do not use this, use SGTREE instead
	static SGTree& getInstance();

	//close the singleton
	void close();

	//set the value of the current matrix
	void setValue(const CMatrix& value);

	//get the value of the current matrix
	CMatrix& getValue();

	//put on pile the current world matrix
	void pop();

	//push from pile to the current world matrx
	void push();

	//dirty all the controller to calculate the next iteration
	void dirty();

	//traverse the tree and update all the nodes
	void traversal();

	//set the root of the tree
	void setRoot(SGNode* root);

	//create a translate node and return its pointer
	SGNodeTranslate* createNodeTranslate();

	//create a separator node and return its pointer
	SGNodeSeparator* createNodeSeparator();

	//create a scale node and return its pointer
	SGNodeScale* createNodeScale();

	//create a rotate node and return its pointer
	SGNodeRotate* createNodeRotate();

	//create a primitive node and return its pointer
	SGNodePrimitive* createNodePrimitive(IPrimitive*);

	//create a meterial node and return its pointer
	SGNodeMaterial* createNodeMaterial(CMaterial*);

	//create a lookat node and return its pointer
	SGNodeLookAt* createNodeLookAt();

	//create a directional light node and return its pointer
	SGNodeDirectionalLight* createNodeDirectionalLight(CDirectionalLight*);

	//create a point light node and return its pointer
	SGNodePointLight* createNodePointLight(CPointLight*);

private:
	//Constructor
	SGTree(void);

	//Destructor
	~SGTree(void);
};

//macro used to get access to the singleton
#define SGTREE SGTree::getInstance()
